﻿using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using SimpleServiceBus.Utilities.ObjectBuilder;

namespace SimpleServiceBus.EndpointManagement.Server.Wcf
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class EndpointManagementServiceBehavior : Attribute, IServiceBehavior
    {
        private readonly Func<IDisposable> _unitOfWorkProvider;
        private readonly IObjectBuilder _objectBuilder;

        public EndpointManagementServiceBehavior(IObjectBuilder objectBuilder,Func<IDisposable> unitOfWorkProvider)
        {
            _objectBuilder = objectBuilder;
            _unitOfWorkProvider = unitOfWorkProvider;
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
                                         Collection<ServiceEndpoint> endpoints,
                                         BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
            {
                var channelDispatcher = cdb as ChannelDispatcher;

                if (channelDispatcher != null)
                {
                    foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
                    {
                        endpointDispatcher.DispatchRuntime.InstanceProvider =
                            new InstanceProvider(serviceDescription.ServiceType,_objectBuilder);

                        foreach (var dispatchOperation in
                            endpointDispatcher.DispatchRuntime.Operations)
                        {
                            dispatchOperation.CallContextInitializers
                                .Add(new UnitOfWorkCallContextInitializer(_unitOfWorkProvider));
                        }
                    }
                }
            }
        }
    }
}
